//world.cpp
#include "world.h"
#include "gamedrawer.h"
#include <vector>
#include <math.h>
#include <string>
#include <Box2d/Box2D.h>

class QueryCallback : public b2QueryCallback
{
public:
	QueryCallback(const b2Vec2& point)
	{
		m_point = point;
		m_fixture = NULL;
	}

	bool ReportFixture(b2Fixture* fixture)
	{
		b2Body* body = fixture->GetBody();
		if (body->GetType() == b2_dynamicBody)
		{
			bool inside = fixture->TestPoint(m_point);
			if (inside)
			{
				m_fixture = fixture;

				// We are done, terminate the query.
				return false;
			}
		}

		// Continue the query.
		return true;
	}

	b2Vec2 m_point;
	b2Fixture* m_fixture;
};

enum _collisionCategory {
ITEM =          0x0001,
CONTAINER =     0x0002,
CONTAINED_ITEM= 0x0004,
BOT =			0x0010
};

World::World(){
	Item::world = this;
	worldSim = new b2World(b2Vec2(0.0f,0.0f));
	temp_Test();
	designate_start = Coord(0,0);
	designate_end = Coord(0,0);
	designate_started = false;
	designate = false;
}

//converts from pixels to meters for use with physics
float p2m(float pixelsIn){
	return float(pixelsIn * 0.1);
}

//converts from meters pixels for drawing
float m2p(float metersIn){
	return float(metersIn * 10);
}

float p2m(int pixelsIn){
	return float(pixelsIn * 0.1);
}

//converts from meters pixels for drawing
float m2p(int metersIn){
	return float(metersIn * 10);
}

b2Vec2 p2m(b2Vec2 pixelsIn){
	pixelsIn.x = p2m(pixelsIn.x);
	pixelsIn.y = p2m(pixelsIn.y);
	return pixelsIn;
}

b2Vec2 m2p(b2Vec2 metersIn){
	metersIn.x = m2p(metersIn.x);
	metersIn.y = m2p(metersIn.y);
	return metersIn;
}

void World::temp_Test(){
	camera_x = 512;
	camera_y = 384;
	definitions = Definition::parseFile("Data\\blueprints.txt");
	printf("definitions: %i\n",definitions.size());
	vector<Definition *> items = Definition::parseFile("Data\\items.txt");
	definitions.insert(definitions.end(), items.begin(), items.end());
	printf("definitions: %i\n",definitions.size());
	Container * c1 = new Container(b2Vec2((float)50.0,50.0));
	Container * c2 = new Container(b2Vec2((float)25.0,25.0));
	Container * c3 = new Container(b2Vec2((float)25.0,50.0));
	addItem(c1);
	addItem(c2);
	addItem(c3);
	for(int i = 0; i < 2; i++){
		Bot * cb = new Bot(b2Vec2(19.0,float(14+p2m(i))));
		addItem( cb );
	}
	for(int i = 0; i < 120; i++){
		GenericItem * gi = new GenericItem("ore1", b2Vec2((float)60+.001f*i,(float)30+.001f*i));
		addItem( gi );
	}
	//add crystals to containers
	GenericItem * gi = new GenericItem("crystal1", b2Vec2(50,50));
	addItem( gi );
	c1->addItem( gi );
	gi = new GenericItem("crystal1", b2Vec2(25,25));
	addItem( gi );
	c2->addItem( gi );
	gi = new GenericItem("crystal1", b2Vec2(25,50));
	addItem( gi );
	c3->addItem( gi );

	//add blueprints to containers
	Blueprint * bp = new Blueprint("blueprint:smelter",b2Vec2(50,50));
	c1->addItem( bp );
	addItem( bp );
	bp = new Blueprint("blueprint:metalworks",b2Vec2(25,25));
	c2->addItem( bp );
	addItem( bp );
	bp = new Blueprint("blueprint:bot factory",b2Vec2(25,50));
	c3->addItem( bp );
	addItem( bp );

	//add Storage to the containers
	Storage * store;
	for(int i = 0; i < 3; i++){
		store = new Storage("ore1",b2Vec2(50,51));
		c1->addItem(store);
		addItem(store);
	}
	for(int i = 0; i < 3; i++){
		store = new Storage("metal1",b2Vec2(51,50));
		c1->addItem(store);
		addItem(store);
	}
	for(int i = 0; i < 4; i++){
		store = new Storage("metal1",b2Vec2(26,25));
		c2->addItem(store);
		addItem(store);
	}
	for(int i = 0; i < 4; i++){
		store = new Storage("metal1 plate",b2Vec2(25,26));
		c2->addItem(store);
		addItem(store);
	}	
	for(int i = 0; i < 4; i++){
		store = new Storage("metal1 plate",b2Vec2(26,50));
		c3->addItem(store);
		addItem(store);
	}

}

void World::createRequest(Container * caller, string message, ItemStack itemstack){
	Request * r = new Request(caller, message, itemstack);
	if(message.compare("want")==0){
		requests.push_back(r);
		printf("Now %i requests in queue.\n",requests.size());
	}
	else if(message.compare("offer")==0){
		//offers.push_back(r);
		//createJobs();
	}
	createJobs();
}

void World::registerStack(ItemStack * is){
	for(unsigned int i = 0; i < inventories.size(); i++){
		if(is == inventories[i]){
			return;
		}
	}
	inventories.push_back(is);
}
void World::unregisterStack(ItemStack * is){
	for(unsigned int i = 0; i < inventories.size(); i++){
		if(is == inventories[i]){
			inventories.erase(inventories.begin()+i);
		}
	}	
}
/*
There are bots, requests, and inventories.
This function attempts to find inventories that match each request.
If the inventory has the right type for the request, but not enough of it,
then that entire inventory is claimed and the function attempts to complete the
request with other inventories.
If a request is completed, it is removed from the requests list.
*/
void World::createJobs(){
	//a job is created when a request can be matched to its value from the inventories	
	for(unsigned int i = 0; i < requests.size(); i++){
		int possibleJobs = idleBots.size()<requests[i]->itemStack.count ? idleBots.size() : requests[i]->itemStack.count;
		createDeliveryJobs(possibleJobs,i);
	}
	for(unsigned int i = 0; i < requests.size(); i++){
		unsigned int possibleJobs = idleBots.size()<requests[i]->itemStack.count ? idleBots.size() : requests[i]->itemStack.count;
		createCollectJobs(possibleJobs,i);
	}
	matchJobToBot();
}
void World::createDeliveryJobs(unsigned int amountToFind, unsigned int i){	
	for(unsigned int j = 0; j < inventories.size(); j++){
		int jobsToMake = 0;
		if(requests[i]->requester!=inventories[j]->owner && requests[i]->itemStack.type.compare(inventories[j]->type)==0){				
			if(inventories[j]->count>=amountToFind){
				jobsToMake = amountToFind;
			}
			else{
				jobsToMake = inventories[j]->count;
			}
			while(jobsToMake > 0 && inventories[j]!=NULL && inventories[j]->count>0){
				Job job = Job();
				job.cargo = requests[i]->itemStack.type;
				job.source = inventories[j]->owner;
				job.destination = requests[i]->requester;
				job.jobType = "deliver";
				requests[i]->itemStack.count--;
				inventories[j]->owner->reserve(requests[i]->itemStack.type,amountToFind);
				jobs.push_back(job);
				jobsToMake--;
				matchJobToBot();
			}				
		}
		if (requests[i]->itemStack.count<=0){
			requests.erase(requests.begin()+i);
			break;
		}
	}
}
//right now this is going through way too much stuff- it needs to break out of the loop in the right place
void World::createCollectJobs(unsigned int possibleJobs, unsigned int i){
	//attempt to find collectable items to meet this request
	for(unsigned int j = 0; j < designatedItems.size(); j++){
		if(designatedItems[j]->name.compare(requests[i]->itemStack.type)==0){
			Job job = Job();
			job.cargo = requests[i]->itemStack.type;
			job.source = designatedItems[j];
			job.destination = requests[i]->requester;
			job.jobType = "collect";
			requests[i]->itemStack.count--;
			jobs.push_back(job);
			//remove the items from the designation list as they are matched to a job
			designatedItems.erase(designatedItems.begin()+j);
			matchJobToBot();
			if (requests[i]->itemStack.count<=0){
				//if the request is met, delete it
				requests.erase(requests.begin()+i);
				printf("job created\n");
				break;
			}
		}
	}
	
	
}

void World::addItem(Item * itm){
	itemList.push_back(itm);
}

void World::select(){
	b2Vec2 &p = b2Vec2(p2m(mouse_get_world_position().x),p2m(mouse_get_world_position().y));	
	b2Vec2 m_mouseWorld;
	b2MouseJoint *m_mouseJoint;
	m_mouseJoint = NULL;
	m_mouseWorld = p;	
	if (m_mouseJoint != NULL)
	{
		return;
	}

	// Make a small box.
	b2AABB aabb;
	b2Vec2 d;
	d.Set(0.001f, 0.001f);
	aabb.lowerBound = p - d;
	aabb.upperBound = p + d;
	// Query the world for overlapping shapes.
	QueryCallback callback(p);
	
	worldSim->QueryAABB(&callback, aabb);

	if (callback.m_fixture)
	{
		deselect_all();
		b2Body* body = callback.m_fixture->GetBody();
		selected.push_back((Item *)body->GetUserData());
		cout<< selected.back()->name<<endl;
	}
	else{
		deselect_all();
	}
	//handles designation state
	if (designate){
		designate_started = true;
		designate_start = mouse_get_world_position();
	}
}

void World::deselect_all(){
	selected.clear();
}
void World::grab(int x, int y){

}

void World::drag(){
}

void World::release(){
	if(designate && designate_started){
		designate_end = mouse_get_position();
		designate = false;
		designate_started = false;
		do_designate();
	}
}
void World::do_designate(){
	vector<Item*> items = vector<Item*>();
	Coord TL;
	Coord BR;
	if(designate_start.x<designate_end.x){
		//tl->br sweep
		if(designate_start.y>designate_end.y){
			TL.x = designate_start.x;
			TL.y = designate_start.y;
			BR.x = designate_end.x;
			BR.y = designate_end.y;
		}
		else{//bl->tr sweep
			TL.x = designate_start.x;
			TL.y = designate_end.y;
			BR.x = designate_end.x;
			BR.y = designate_start.y;			
		}
	}
	else{
		//tr->bl sweep
		if(designate_start.y>designate_end.y){
			TL.x = designate_end.x;
			TL.y = designate_start.y;
			BR.x = designate_start.x;
			BR.y = designate_end.y;	
		}
		else{//br->tl sweep
			TL.x = designate_end.x;
			TL.y = designate_end.y;
			BR.x = designate_start.x;
			BR.y = designate_start.y;			
		}	
	}
	getAt("", &items, 0, TL, BR);
	for(unsigned int i = 0; i < items.size(); i++){
		designatedItems.push_back(items[i]);//problem: doesn't check for duplicates
		createJobs();
	}
}
void World::toggle_designate(){
	if(designate){
		designate = false;
		designate_started = false;
	}
	else{
		designate = true;
	}
}

void World::update(){

	float timeStep = 1.0f/60.0f;
	int velocityIterations = 8;
	int positionIterations = 10;
	worldSim->Step(timeStep, velocityIterations, positionIterations);
	for(unsigned int i = 0; i<itemList.size();i++){
		if(itemList[i]!=NULL){
			itemList[i]->update();
		}	
	}
}

void World::draw(){
	for(vector<Item *>::iterator itr = designatedItems.begin(); itr != designatedItems.end(); itr++){
		b2Body * bb = (*itr)->body;
		fill(Color(0.75f,0.75f,1.0f,0.5f));
		noStroke();
		b2Vec2 pos = bb->GetPosition();
		float radius = (*itr)->drawRadius;
		drawCircle(m2p(pos.x),m2p(pos.y),radius);
		noFill();
		noStroke();
	}
	for(vector<Item *>::iterator itr = itemList.begin(); itr != itemList.end(); itr++){
		(*itr)->draw();
	}
	for(vector<Item *>::iterator itr = selected.begin(); itr != selected.end(); itr++){
		b2Body * bb = (*itr)->body;
		stroke(Color(0.5f,1.0f,0.5f));
		noFill();
		b2Vec2 pos = bb->GetPosition();
		float radius = (*itr)->drawRadius;
		drawCircle(m2p(pos.x),m2p(pos.y),radius);
	}

	fill(Color(255,55,55));
	noStroke();
	drawCircle(get_camera_x(),get_camera_y(),5);
	noFill();

/*debug*/
	Coord pos = Coord(10,600);
	Color c = Color(255,255,255);
	string s = "";
	for(unsigned int i = 0; i < itemList.size(); i++){				
		if (itemList[i]->name.compare("cargo bot")==0) {
			Bot * b = static_cast<Bot*>(itemList[i]);
			s = itemList[i]->name.c_str();		
			pos.y-=12;pos.y-=12;
			renderBitmapString( pos, &s, c);
			pos.y-=12;
			s = "status: ";
			s.append(b->state);
			renderBitmapString( pos, &s, c);
			s = "cargo: ";
			if(b->cargo!=NULL){
				s.append(b->cargo->name.c_str());
			}
			else{
				s.append("none");
			}
			pos.y-=12;
			renderBitmapString( pos, &s, c);
		}
	}
	pos = Coord(650,600);
	s = "requests: ";
	renderBitmapString( pos, &s, c);
	for(unsigned int i = 0; i < requests.size(); i++){
		pos.y-=12;
		s = requests[i]->itemStack.type.c_str();
		renderBitmapString( pos, &s, c);
	}
	pos = Coord(650,500);
	s = "jobs: ";
	renderBitmapString( pos, &s, c);
	for(unsigned int i = 0; i < jobs.size(); i++){
		pos.y-=12;
		s = jobs[i].cargo.c_str();
		renderBitmapString( pos, &s, c);
	}

}

void World::order_duplicate(){
	for(vector<Item *>::iterator itr = selected.begin(); itr != selected.end(); itr++){
		(*itr)->command("duplicate");		
	}
}
void World::order_convert(){
	for(vector<Item *>::iterator itr = selected.begin(); itr != selected.end(); itr++){
		(*itr)->command("convert");		
	}
}

void World::order_toggle_active_state(){
	for(vector<Item *>::iterator itr = selected.begin(); itr != selected.end(); itr++){
		(*itr)->command("toggle active state");		
	}
}
b2Body * World::createBody(Item * itemIn, b2Vec2 pointIn, b2Shape * shapeIn){
	//body
	b2Body * body;
	b2BodyDef bodydef = b2BodyDef();
	bodydef.type =  b2_dynamicBody;
	bodydef.position.Set(pointIn.x, pointIn.y);	
	bodydef.angle = 0.0f;
	bodydef.linearDamping = 0.5f;
	bodydef.angularDamping = 0.01f;
	bodydef.allowSleep = true;
	bodydef.awake = true;
	bodydef.fixedRotation = false;
	bodydef.bullet = false;
	bodydef.userData = itemIn;
	body = worldSim->CreateBody(&bodydef);

	//fixture
	b2FixtureDef fixturedef;
	fixturedef.shape = shapeIn;
	fixturedef.density = 1.0f;
	uint16 categoryBits;
	uint16 maskBits;
	categoryBits = ITEM;
	maskBits = (ITEM|CONTAINER);	
	for(unsigned int i = 0 ; i < itemIn->tags.size(); i++){		
		if(itemIn->tags[i].compare("container")==0){
			categoryBits = CONTAINER;
			maskBits = (ITEM|CONTAINER);			
		}
		if(itemIn->tags[i].compare("bot")==0){
			categoryBits = BOT;
			maskBits = (BOT);			
		}
	}
	fixturedef.filter.categoryBits = categoryBits;
    fixturedef.filter.maskBits = maskBits;
	fixturedef.filter.groupIndex = 0;

	b2Fixture * myFixture = body->CreateFixture(&fixturedef);

	return body; 
}

//Check items in itemList for s, if found, add to foundList. Do until [count] have been found.
//Returns true if [count] items have been found, false if not.
//a count of 0 means "get all"
bool World::get(string s, vector<Item*>* foundList, int count){
	int counted = 0;
	for(unsigned int i = 0; i<itemList.size(); i++){
		if(itemList[i]->name.compare(s)==0||itemList[i]->hasTag(s)){		
			foundList->push_back(itemList[i]);
			counted++;
			if(count>0 && counted==count){
				return true;
			}
		}
	}	
	return(counted==count);
}

//returns only items within a given area designated by a pair of coords (top left, bottom right)
bool World::getAt(string s, vector<Item*>* v, int count, Coord TL, Coord BR){
	int counted = 0;
	vector<Item*> temp;
	get(s,&temp,count);
	for(unsigned int i = 0; i < temp.size(); i++){
		b2Vec2 point = temp.at(i)->body->GetPosition();
		if(point.x>p2m(TL.x)&&point.x<p2m(BR.x)&&point.y<p2m(TL.y)&&point.y>p2m(BR.y)){
			v->push_back(temp.at(i));
			counted++;
			if (count<0 && counted==count){
				return true;
			}
		}
	}
	return(counted==count);
}

vector<string> World::getDef(string defName){
	for(unsigned int i = 0; i < definitions.size(); i++){
		if(definitions[i]->name.compare(defName)==0){
			return definitions[i]->lines;
		}
	}	
	vector<string> error;
	string myError = "type not recognized:";
	myError.append(defName.c_str());
	error.push_back(myError);
	return error;
}

void World::removeItem(Item * itm){
	int found = 0;
	for(unsigned int i = 0; i < itemList.size(); i++){
		if(itemList.at(i) == itm){
			itemList.at(i)->~Item();
			itemList.erase(itemList.begin()+i);
			found = 1;
			break;
		}
	}
	for(unsigned int i = 0; i < selected.size(); i++){
		if(selected.at(i) == itm){
			selected.erase(selected.begin()+i);
			break;
		}
	}
}

void World::addIdleBot(Bot * botIn){
	idleBots.push_back(botIn);
	createJobs();
}

void World::matchJobToBot(){
	while(!idleBots.empty() && !jobs.empty()){
		//give the first job to the first bot		
		idleBots.back()->setJob(jobs.back());
		idleBots.pop_back();
		jobs.pop_back();
		
	}
}

int Item::next_ID = 0;
World * Item::world = NULL;

bool Item::hasTag(string tag){
	for(unsigned int i = 0; i < tags.size(); i++){
		if(tags[i].compare(tag)==0){
			return true;
		}
		else if (tag.compare("")==0){
			return true;
		}
	}
	return false;
}

void Item::defaultDraw(){
	if(body == NULL){
		return;
	}
	b2Vec2 pos = m2p(body->GetPosition());
	useTexture(textureID);
	float x1 = pos.x-3*drawRadius/2;
	float y1 = pos.y-3*drawRadius/2;
	float x2 = pos.x+3*drawRadius/2;
	float y2 = pos.y+3*drawRadius/2;
	drawRect(x1,y1,x2,y2);
	noTexture();
	if(owner!=NULL){
		b2Vec2 pos2 = m2p(owner->body->GetPosition());
		stroke(Color(0,0,0));
		drawLine(pos.x,pos.y,pos2.x,pos2.y,Color(120,120,200,200),1);
	}
}

void GenericItem::update(){}
void GenericItem::draw(){
	stroke(Color(0.0f,0.0f,0.0f,0.6f));
	fill(Color(255,255,255,200));
	if(owner!=NULL){
		fill(Color(195,195,195,200));
	}
	defaultDraw();
	noFill();
}
void GenericItem::command(string ss){}
void Item::generateShape(string defName){
	vector<string> lines;
	string str;
	lines = world->getDef(defName);
	shape.m_p = b2Vec2(0,0);
	for(unsigned int i = 0; i<lines.size();i++){
		str = lines[i];
		if(str.compare(0,5,"name:")==0){
			name = str.substr(5,str.size());
		}
		else if(str.compare(0,12,"draw_radius:")==0){
			drawRadius = (float)atof(str.substr(12,str.size()-12).c_str());
		}
		else if(str.compare(0,12,"texture_file")==0){
			string texname = str.substr(13,str.size()-13).c_str();
			textureID = findTexture(texname);
			if (textureID==0){
				printf("Could not find texture: %s\n",texname.c_str());
			}

		}
		else if(str.compare(0,15,"physics_radius:")==0){
			shape.m_radius = (float)atof(str.substr(15,str.size()-15).c_str());

		}
		else if(str.compare(0,5,"tags:")==0){		
			size_t nextComma = str.find_first_of(",",5);
			size_t lastComma = nextComma;
			tags.push_back(str.substr(5,nextComma-5));
			while(nextComma!=string::npos){
				lastComma = nextComma;
				nextComma = str.find_first_of(",",lastComma+1);
				tags.push_back(str.substr(lastComma+1,nextComma-(lastComma+1)));
			}
		}
	}
}
/*Blueprint*/

void Blueprint::update(){
	if(duplication_cycle_timer > 0){
		duplicate();
	}
	else if (conversion_cycle_timer > 0){
		convert();
	}
}
void Blueprint::draw(){
	if(body == NULL){
		return;
	}
	stroke(Color(0.9f,0.9f,1.0f,0.6f));
	if(duplication_cycle_timer > 2){
		fill(Color(255-(125*duplication_cycle_timer/duplication_time),255-(125*duplication_cycle_timer/duplication_time),0));
	}
	else if(conversion_cycle_timer > 2){
		fill(Color(255,125,125));
	}
	else{
		fill(Color(125,125,255));
	}
	b2Vec2 pos = body->GetPosition();
	drawCircle(m2p(pos.x),m2p(pos.y),drawRadius);
	defaultDraw();
	if(duplication_cycle_timer > 1){
		fill(Color(125,125,255));
		drawCircle(m2p(pos.x),m2p(pos.y),(drawRadius*duplication_cycle_timer+1)/(duplication_time+1));
	}
	else if(conversion_cycle_timer > 1){
		fill(Color(155,50,50));
		drawCircle(m2p(pos.x),m2p(pos.y),(drawRadius*conversion_cycle_timer+1)/(conversion_time+1));
	}
	noFill();
}
void Blueprint::command(string commandIn){
	if(commandIn.compare("duplicate")==0){
		if(duplication_cycle_timer == 0 && conversion_cycle_timer == 0){
			duplication_cycle_timer = 1;
		}
	}
	if(commandIn.compare("convert")==0){
		if(duplication_cycle_timer == 0 && conversion_cycle_timer == 0){
			conversion_cycle_timer = 1;
		}
	}
}
void Blueprint::duplicate(){
	if(duplication_cycle_timer == 1){//just started	
		if(duplicate_hasInputs()){		
			//remove inputs
			while(held_inputs.size()>0){
				world->removeItem(held_inputs.back());
				held_inputs.pop_back();
			}
			duplication_cycle_timer = 2;
		}
		else{
			duplication_cycle_timer = 0;
		}
	}
	else if(duplication_cycle_timer > 1 && duplication_cycle_timer < duplication_time){//mid-cycle, continue
		duplication_cycle_timer++;
		if(duplication_cycle_timer%10 == 0){
		}
	}
	else if(duplication_cycle_timer >= duplication_time){//done, produce output
		//produce a new Blueprint identical to this one
		Blueprint * a = new Blueprint(name,body->GetPosition());
		a->shape.m_radius = shape.m_radius;
		a->drawRadius = drawRadius;
		world->addItem(a);
		if (owner){
			owner->addItem(a);
		}		
		duplication_cycle_timer = 0;
	}
}
//returns true if all reqired inputs are currently available
bool Blueprint::duplicate_hasInputs(){
	//go though list of required inputs, ask the world if they are all there
	//return true if all there
	held_inputs.clear();
	vector<Item *> temp_vector;
	for(unsigned int i = 0; i < duplication_inputs.size(); i++){
		if(!owner->find(duplication_inputs[i].type,&temp_vector,duplication_inputs[i].count)){
			return false;
		}		
	}

	held_inputs = temp_vector;	
	return true;
}
//returns true if all reqired inputs are currently available
bool Blueprint::conversion_hasInputs(){
	//go though list of required inputs, ask the world if they are all there
	//return true if all there
	held_inputs.clear();
	vector<Item *> temp_vector;
	for(unsigned int i = 0; i < conversion_inputs.size(); i++){
		for(unsigned int j = 0; j < conversion_inputs.size(); j++){
			printf("Looking for %s\n",conversion_inputs[j].type.c_str());
		}
		if(!world->get(conversion_inputs[i].type,&temp_vector,conversion_inputs[i].count)){
			return false;
		}
	}
	held_inputs = temp_vector;	
	return true;
}
void Blueprint::convert(){
	if(conversion_cycle_timer == 1){//just started	
		if(conversion_hasInputs()){	

			//remove inputs
			while(held_inputs.size()>0){
				world->removeItem(held_inputs.back());
				held_inputs.pop_back();
			}
			conversion_cycle_timer = 2;
		}
		else{
			conversion_cycle_timer = 0;
		}
	}
	else if(conversion_cycle_timer > 1 && conversion_cycle_timer < conversion_time){//mid-cycle, continue
		conversion_cycle_timer++;
	}
	else if (conversion_cycle_timer >= conversion_time){//done, produce output- replace Blueprint with a Reactor with the same properties
		world->addItem(new Reactor(this, currentSize));
		conversion_cycle_timer = 0;
	}
}
void Blueprint::generatefromDefinition(string defName){
	string mode;
	vector<string> lines;
	string str;
	lines = world->getDef(defName);
	for(unsigned int i = 0; i<lines.size();i++){
		str = lines[i];
		if(str.compare("[blueprint]")==0){
		//do nothing for now
		}
		else if(str.compare("[duplication]")==0){
			mode = "duplication";
		}
		else if(str.compare("[reaction]")==0){
			mode = "reaction";
		}
		else if(str.compare("[conversion]")==0){
			mode = "conversion";
		}
		else if(str.compare("[/duplication]")==0){
			mode = "no_mode";
		}
		else if(str.compare("[/reaction]")==0){
			mode = "no_mode";
		}
		else if(str.compare("[/conversion]")==0){
			mode = "no_mode";
		}
		if(str.compare("[/blueprint]")==0){
			//do nothing for now
		}
		else if(str.compare(0,5,"name:")==0){
			name = str.substr(5,str.size());
		}
		else if(str.compare(0,13,"current_size:")==0){
			//this mess is just a conversion from a string to a const char to a float
			currentSize = (float)atof(str.substr(13,str.size()).c_str());
		}
		else if(str.compare(0,5,"time:")==0){
			int time = atoi(str.substr(5,str.size()-5).c_str());
			if(mode.compare("duplication")==0){
				duplication_time = time;
			}
			else if(mode.compare("conversion")==0){
				conversion_time = time;
			}
			else if(mode.compare("reaction")==0){
				reaction_time = time;
			}
			else{
			}
		}
		else if(str.compare(0,6,"power:")==0){
			float power = (float)atof(str.substr(6,str.size()).c_str());
			if(mode.compare("duplication")==0){
				duplication_power_consumption = power;
			}
			else if(mode.compare("conversion")==0){
				conversion_power_consumption = power;
			}
			else if(mode.compare("reaction")==0){
				reaction_power_consumption = power;
			}
			else{
			}
		}
		else if(str.compare(0,11,"size_range:")==0){
			size_t firstComma = str.find_first_of(",",11);
			float min = (float)atof(str.substr(11,firstComma-11).c_str());
			float max = (float)atof(str.substr(firstComma+1,str.size()).c_str());
			if(mode.compare("duplication")==0){
			}
			else if(mode.compare("conversion")==0){
				conversion_size_range = b2Vec2(min,max);
			}
			else if(mode.compare("reaction")==0){
				reaction_size_range = b2Vec2(min,max);
			}
			else{
			}
		}
		else if(str.compare(0,6,"input:")==0){
			size_t firstComma = str.find_first_of(",",6);
			int amount = atoi(str.substr(6,firstComma-6).c_str());
			string itemName = str.substr(firstComma+1,str.size());
			ItemStack item = ItemStack(itemName,amount);
			if(mode.compare("duplication")==0){
				duplication_inputs.push_back(item);
			}
			else if(mode.compare("conversion")==0){
				conversion_inputs.push_back(item);
			}
			else if(mode.compare("reaction")==0){
				reaction_inputs.push_back(item);
			}
			else{
			}
		}
		else if(str.compare(0,7,"output:")==0){
			size_t firstComma = str.find_first_of(",",7);
			int amount = atoi(str.substr(7,firstComma-7).c_str());
			string itemName = str.substr(firstComma+1,str.size());
			if(mode.compare("duplication")==0){
			}
			else if(mode.compare("conversion")==0){
			}
			else if(mode.compare("reaction")==0){
				reaction_outputs.push_back(ItemStack(itemName,amount));
			}
			else{
			}
		}
		else if(str.compare(0,12,"texture_file")==0){
			string texname = str.substr(13,str.size()-13).c_str();
			textureID = 0;
			textureID = findTexture(texname);
			if (textureID==0){
				printf("Could not find texture: %s\n",texname.c_str());
			}

		}

	}
}
vector<Definition*> Definition::parseFile(string filename){
	vector<Definition*> defs;
	vector<string> lines;
	ifstream inputFile;
	//string mode;
	inputFile.open(filename);
	string str;
	while(!inputFile.eof()){
		getline(inputFile,str);
		lines.push_back(str);
		if(str.compare("[def]")==0){
		}
		if(str.compare("[/def]")==0){
			Definition * def = new Definition(lines);
			defs.push_back(def);		
			lines.clear();
		}	
	}
	inputFile.close();
return defs;
}
/* Reactor */
void Reactor::draw(){
	stroke(Color(1.0f,1.0f,1.0f,0.6f));
	if(conversion_cycle_timer > 2){
		fill(Color(155,50,50));
		stroke(Color(0.0f,1.0f,1.0f,0.6f));
	}
	else if(reaction_cycle_timer > 2){
		fill(Color(155,80,80));
	}
	else{
		fill(Color(155,50,50));
	}
	
	b2Vec2 pos = m2p(body->GetPosition());

	drawCircle(pos.x,pos.y,drawRadius);
	defaultDraw();
	if(reaction_cycle_timer > 2){
		fill(Color(155,55,55));
		drawCircle(pos.x,pos.y,(drawRadius*reaction_cycle_timer+1)/(reaction_time+1));
	}
	else if(conversion_cycle_timer > 2){
		fill(Color(255,125,125));
		drawCircle(pos.x,pos.y,(drawRadius*conversion_cycle_timer+1)/(conversion_time+1));
	}

	noStroke();
	if(active){
		fill(Color(0,255,0,200));
		drawCircle(pos.x,pos.y,(float)(drawRadius*.1));	
	}
	else{
		fill(Color(255,90,90,200));
		drawCircle(pos.x,pos.y,(float)(drawRadius*.1));	
	}
	noFill();
}
void Reactor::update(){
	if(!active){
		return;
	}
	convert();	
	react();

}
void Reactor::command(string command){
	if (command.compare("convert")==0){
		conversion_cycle_timer = 1;
	}
	else if(command.compare("activate")==0){
		active = true;
	}
	else if(command.compare("deactivate")==0){
		active = false;
	}
	else if(command.compare("toggle active state")==0){
		if(active){
			active = false;
		}
		else{
			active = true;
		}
	}
}
void Reactor::requestInputs(){
	vector<ItemStack> neededItems;
	if(conversion_cycle_timer > 0){
		neededItems = conversionInputsNeeded();
	}
	else if(reaction_cycle_timer > 0){
		neededItems = reactionInputsNeeded();
	}
	else{
		printf("[error?]requestInputs() called and neither reaction nor conversion is occurring\n");
		return;
	}
	//compare the needed items list to the pending list.
	//if more of an item are needed than are pending, add a request
	//if the item is not on the pending list, add a request
	for(unsigned int i = 0; i < neededItems.size(); i++){
		int count = neededItems[i].count;//this is how many items of the type we need
		for(unsigned int j = 0; j < pending_requests.size(); j++){
			//if more of an item are needed than are pending, add a request
			if(pending_requests[j].type.compare(neededItems[i].type)==0){
				count-=pending_requests[j].count;
			}
		}
		//if the item is not on the pending list, add a request
		if(count > 0){
			ItemStack is = ItemStack(neededItems[i].type, count); 
			addPendingRequest(is);
			world->createRequest(owner,"want", is);
		}
	}
	inputs_changed = false;
}
//add a request for an ItemStack
void Reactor::addPendingRequest(ItemStack is){
		for(unsigned int i = 0; i < pending_requests.size(); i++){
			if(pending_requests[i].type.compare(is.type)==0){
				pending_requests[i].count += is.count;
				return;
			}
		}
		pending_requests.push_back(is);
}
void Reactor::react(){
	float input_angle = 6.28f;
	float output_angle = 0;
	if(reaction_cycle_timer < 1){
		if(!inputs_changed){
			return;
		}
		else{
			reaction_cycle_timer = 1;
			if(!canClaimInputs()){
				return;
			}
		}
	}
	if(reaction_cycle_timer == 1){//just started
		vector<ItemStack> is = reactionInputsNeeded();
		if(is.empty()){//if no inputs needed
			for(unsigned int i = 0; i < held_inputs.size(); i++){
				Item * itm =  held_inputs[i];
				b2DistanceJointDef jointdef;
				jointdef.bodyA = itm->body;
				jointdef.bodyB = this->body;
				jointdef.collideConnected = true;
				jointdef.localAnchorA = b2Vec2(this->shape.m_radius,0);
				jointdef.localAnchorB.Set(0,0);
				world->worldSim->CreateJoint(&jointdef);
				b2Fixture * fix = itm->body->GetFixtureList();
				b2Filter filter = b2Filter(fix->GetFilterData());
				filter.categoryBits = ITEM;
				filter.maskBits = ITEM;
				fix->SetFilterData(filter);
			}
			pending_requests.clear();
			reaction_cycle_timer = 2;
			printf("Stage 2 started.\n");
		}
		else{
			requestInputs();
			reaction_cycle_timer = 0;			
		}
	}
	else if(reaction_cycle_timer == 2){
		//remove inputs
		for(unsigned int i = 0; i < held_inputs.size(); i++){
			for (b2ContactEdge * ce = held_inputs[i]->body->GetContactList(); ce; ce = ce->next){
				Item * item = held_inputs[i];

				if(ce->other == this->body){			
					held_inputs.erase(held_inputs.begin()+i);
					owner->erase(item);
					break;
				}					
			}
		}
		if(held_inputs.size()==0){
			reaction_cycle_timer = 3;
			printf("Stage 3 started.\n");
		}
	}
	else if(reaction_cycle_timer > 1 && reaction_cycle_timer < reaction_time){//mid-cycle, continue
		reaction_cycle_timer++;
	}
	else if(reaction_cycle_timer >= reaction_time){//done, produce output
		//produce outputs
		for(unsigned int i = 0; i<reaction_outputs.size(); i++ ){
			for (unsigned int j = 0; j < reaction_outputs[i].count; j++){			
				b2Vec2 modPosition = body->GetPosition();
				modPosition.x += (float)0.0001;
				//this line needs to be improved to be less stupid
				Item * a;
				if(reaction_outputs[i].type.compare("cargo bot")==0){
					a = new Bot(modPosition);
				}
				else{
					a = new GenericItem(reaction_outputs[i].type,modPosition);
					owner->addItem(a);
				}
				world->addItem(a);
			}
		}		
		reaction_cycle_timer = 0;
		printf("Reaction complete.\n");
	}
}
void Reactor::convert(){
	if(conversion_cycle_timer <1){
		return;
	}
	if(conversion_cycle_timer == 1){//just started	
		if(conversionInputsNeeded().empty()){//if no inputs are needed		
			//remove inputs
			while(held_inputs.size()>0){
				world->removeItem(held_inputs.back());
				held_inputs.pop_back();
			}
			conversion_cycle_timer = 2;
		}
		else{
			conversion_cycle_timer = 0;
		}
	}
	else if(conversion_cycle_timer > 1 && conversion_cycle_timer < conversion_time){//mid-cycle, continue
		conversion_cycle_timer++;
	}
	else if (conversion_cycle_timer >= conversion_time){//done, produce output- replace Blueprint with a Reactor with the same properties
		Blueprint * bp = new Blueprint(blueprint,body->GetPosition());
		world->addItem(bp);
		owner->addItem(bp);
		conversion_cycle_timer = 0;
		owner->unregisterObserver(this);
		world->removeItem(this);
		
	}
}

vector<ItemStack> Reactor::conversionInputsNeeded(){
	vector<Item *> temp_vector;
	vector<ItemStack> item_prep;
	for(unsigned int i = 0; i < conversion_inputs.size(); i++){
		temp_vector.clear();
		if(!owner->find(conversion_inputs[i].type,&temp_vector,conversion_inputs[i].count)){
			//if not enough, add an ItemStack saying that we need amount-we-need - amount-we-have, of Item
			item_prep.push_back(ItemStack(conversion_inputs[i].type,conversion_inputs[i].count-temp_vector.size()));
		}
	}
	return item_prep;
}
vector<ItemStack> Reactor::reactionInputsNeeded(){
	vector<Item *> temp_vector;
	vector<ItemStack> item_prep;
	for(unsigned int i = 0; i < reaction_inputs.size(); i++){
		temp_vector.clear();
		if(!owner->find(reaction_inputs[i].type,&temp_vector,reaction_inputs[i].count)){
			//if not enough, add an ItemStack saying that we need amount-we-need - amount-we-have, of Item
			item_prep.push_back(ItemStack(reaction_inputs[i].type,reaction_inputs[i].count-temp_vector.size()));
		}
	}
	return item_prep;
}
void Reactor::notify(){
	inputs_changed = true;
}

bool Reactor::canClaimInputs(){
	bool returnvalue = false;
	held_inputs.clear();
	if(reaction_cycle_timer > 0 || conversion_cycle_timer > 0){
		pending_requests.empty();
	}
	if(reaction_cycle_timer > 0){
		for(unsigned int i= 0; i < reaction_inputs.size(); i++){
			returnvalue = owner->find(reaction_inputs[i].type,&held_inputs,reaction_inputs[i].count);				
			if (!returnvalue){
				return false;
			}
		}

		return true;
	}
	else if(conversion_cycle_timer > 0){
		for(unsigned int i= 0; i < conversion_inputs.size(); i++){
			returnvalue = owner->find(conversion_inputs[i].type,&held_inputs,conversion_inputs[i].count);				
			if (!returnvalue){
				return false;
			}
		}
		return true;
	}
	return false;
}

/* Container */

bool Container::find(string itemToFind, vector<Item*>* foundList, unsigned int count){
	//go through the list of items
	//if the item matches the item to get, add it to the found list
	//repeat until count is satisfied
	int counted = 0;
	for(unsigned int i = 0; i<internal_items.size(); i++){
		if(internal_items[i]->name.compare(itemToFind)==0){
			foundList->push_back(internal_items[i]);
			counted++;
			if(counted==count){
				return true;
			}
		}
	}
	return(counted==count);
}

//returns a reference to the ItemStack for the desired item
//if not found, returns NULL
ItemStack * Container::find(string itemToFind){

	for(unsigned int i = 0; i < inventory.size(); i++){
		if(itemToFind.compare(inventory[i]->type)==0){
			return inventory[i];
		}
	}
	return NULL;
}


void Container::update(){
	
}
void Container::draw(){
	defaultDraw();
	stroke(Color(55,55,255,100));
	fill(Color(200,100,255,30));
	b2Vec2 pos = m2p(body->GetPosition());
	float angle = body->GetAngle();
	float r = m2p(shape.m_radius);
	drawLine(pos.x,pos.y,pos.x+r*cos(angle),pos.y+r*sin(angle),Color(0,255,0));
	noFill();
	
}
void Container::command(string strIn){

}

//in: the type of thing to reserve, the number
//out: the number sucessfully reserved
//this function moveves items from the inventory to the reserved list
unsigned int Container::reserve(string type, unsigned int amountWanted){
	 int numberReserved = 0;
	 //if I have enough in my inventory for the entire count,
	 ItemStack * stack = find(type);
	 if(stack == NULL){return 0;}//if I can't find any, I can't reserve any
	 if(stack->count>=amountWanted){
		 numberReserved = amountWanted;
		 changeInventory(type,-(int)amountWanted);
	 }
	 else{
		numberReserved = stack->count;
		changeInventory(type,-(int)stack->count);
	 }

	 return numberReserved;
}

//gives an item to a bot without deleting it
Item * Container::take(Bot * taker, string itemToTake){
	for(unsigned int i = 0; i < internal_items.size(); i++){
		if(internal_items[i]->name.compare(itemToTake)==0){
			changeReservedInventory(itemToTake,-1);
			Item * temp = internal_items[i];
			detach(temp);
			temp->owner = NULL;
			internal_items.erase(internal_items.begin()+i);
			return temp;
		}
	}
	return NULL;
}

void Container::changeReservedInventory(string itemName, int change){
	for(unsigned int i = 0; i < reserved_inventory.size(); i++){
		if(reserved_inventory[i]->type.compare(itemName)==0){
			reserved_inventory[i]->count+=change;
			if (reserved_inventory[i]->count<=0){
				reserved_inventory.erase(reserved_inventory.begin()+i);
			}
		}
	}
	//else, make a new stack with the item
	if(change > 0){
		ItemStack * newStack = new ItemStack(itemName,change);
		reserved_inventory.push_back(newStack);
	}		
}

void Container::changeInventory(string itemName, int change){
	//if the item already exist in the inventory, change its stack
	for(unsigned int i = 0; i < inventory.size(); i++){
		if(inventory[i]->type.compare(itemName)==0){
			inventory[i]->count+=change;
			if (inventory[i]->count<=0){
				world->unregisterStack(inventory[i]);
				inventory.erase(inventory.begin()+i);
			}
		}
	}
	//else, make a new stack with the item
	if(change > 0){
		ItemStack * newStack = new ItemStack(itemName,change);
		newStack->owner = this;
		inventory.push_back(newStack);
		world->registerStack(newStack);
	}
	notifyObservers();//let any observers know that the inventory has changed
}

void Container::addItem(Item * item){
	item->owner = this;
	internal_items.push_back(item);
	attach(item);
	if(item->hasTag("wall section")){
		wall_sections.push_back(item);
		world->worldSim->DestroyBody(item->body);
	}
	else{
		changeInventory(item->name,1);
	}
}

void Container::attach(Item * item){
	b2DistanceJointDef jointdef;
	jointdef.bodyA = item->body;
	jointdef.bodyB = this->body;
	jointdef.collideConnected = true;
	jointdef.localAnchorA = b2Vec2(0,p2m(this->drawRadius+item->drawRadius));
	jointdef.localAnchorB.Set(0,p2m(this->drawRadius));
	world->worldSim->CreateJoint(&jointdef);
}

void Container::detach(Item* item){
	b2JointEdge * je = item->body->GetJointList();
	while(je->other!=this->body){
		je = je->next;
	}
	world->worldSim->DestroyJoint(je->joint);
}

void Container::erase(Item * itm){
	//find the item and remove it from the list
	for(unsigned int i = 0; i < internal_items.size(); i++){
		if(itm == internal_items[i]){
			changeInventory(itm->name,-1);
			internal_items.erase(internal_items.begin()+i);
			world->removeItem(itm);
			return;
		}
	}
}

void Container::calculateSize(){
	double circ = 0;
	for(unsigned int i = 0; i<wall_sections.size(); i++){
		circ+=wall_sections[i]->shape.m_radius;
	}
	circ = circ/3.1;
	for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext())
	{
		if(!f->GetNext()){
			f->GetShape()->m_radius = (float)circ;
		}
	}
	body->GetFixtureList()->GetShape()->m_radius = (float)circ;
	//this->drawRadius = p2m((float)circ);
	//body->ApplyTorque(10000);
	//body->ApplyForceToCenter(b2Vec2(10000,0));
}

void Container::arrangeWalls(){
	calculateSize();
	float parent_radius = body->GetFixtureList()->GetShape()->m_radius;
	float current_angle = 0;
	//float separation = 6.28319/wall_sections.size();
	bool first = true;
	for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext())
	{
		if(!first){
			float child_radius = 0;
			child_radius = f->GetShape()->m_radius;
			current_angle += (child_radius)/(parent_radius);//half
			b2Vec2 parent_point = body->GetPosition();
			float x = sin(current_angle)*(parent_radius);
			float y = cos(current_angle)*(parent_radius);
			b2CircleShape * circle = static_cast<b2CircleShape*>(f->GetShape());
			circle->m_p.Set(x,y);
			current_angle += (child_radius)/(parent_radius);//the other half
			
		}
		first = false;
	}

}

/**Storage**/
/*The storage item does two things:
	1) It keeps a list of the things it is storing, making them available to its owner
	2) It attempts to maintain a specific amount of the things it is storing, offering inventories
	when it wants to reduce the amount, and sending want messages if the amount is too low

	For now it will also serve as the delivery point for Bots until the Docking Bay is added.
*/
Storage::Storage(string typeIn, b2Vec2 pointIn){
	type = typeIn;
	generateShape("storage");
	body = world->createBody(this, pointIn, &shape);
};
void Storage::command(string){}
void Storage::update(){}
void Storage::draw(){
	defaultDraw();
}

/**Bot**/
void Bot::notify(){
	state = "pickup";
	target = job.source->body->GetPosition();
}

void Bot::update(){
	if (state.compare("idle")==0){

	}
	else if (state.compare("pickup")==0){
		doPickup();
	}
	else if (state.compare("deliver")==0){
		doDeliver();		
	}
	else if (state.compare("collect")==0){
		doCollect();
	}
}
void Bot::draw(){
	defaultDraw();
	noFill();
	if(state.compare("pickup")==0){
		stroke(Color(0,0,255));
	}
	else{
		stroke(Color(255,0,0));
	}
	drawCircle(m2p(target.x),m2p(target.y),m2p(2.5f));
	b2Vec2 position = m2p(body->GetPosition());
	b2Vec2 target_p = m2p(target);
	b2Vec2 vel = m2p(body->GetLinearVelocity());
	drawLine(position.x,position.y,target_p.x,target_p.y,Color(0,255,0),2);//line to target
	drawLine(position.x,position.y, position.x+vel.x, position.y+vel.y,Color(255,0,0),2);//velocity
}
void Bot::command(string cmd){}



void Bot::doDeliver(){
	string cargoname = cargo->name;
	if (!moveTowardTarget()){
		dropOff();
		printf("Cargo delivered: %s\n",cargoname.c_str());
		state = "idle";
		world->addIdleBot(this);
	}
}

void Bot::doPickup(){
	if (!moveTowardTarget()){//attempt to move to the target. once there, get the cargo
		if(job.jobType.compare("deliver")==0){
			Container * c = static_cast<Container*>(job.source);
			cargo = c->take(this, job.cargo);
		}
		else if(job.jobType.compare("collect")==0){			
			cargo = job.source;
		}
		if(cargo!=NULL){
			attach(cargo);
			target = job.destination->body->GetPosition();
			state = "deliver";
		}
		else{
			state = "idle";
			world->addIdleBot(this);
		}
	}
}

void Bot::doCollect(){
	if (!moveTowardTarget()){//attempt to move to the target. once there, get the cargo
		cargo = job.source;
		attach(cargo);
		target = job.destination->body->GetPosition();
		state = "deliver";
	}	
}

void Bot::dropOff(){
	job.destination->addItem(cargo);
	detach(cargo);
	cargo = NULL;
}

void Bot::setJob(Job j){
	job = j;
	notify();
}

void Bot::attach(Item * item){
	b2DistanceJointDef jointdef;
	jointdef.bodyA = item->body;
	jointdef.bodyB = this->body;
	jointdef.collideConnected = false;
	jointdef.localAnchorA = b2Vec2(0,1);//b2Vec2(0,p2m(this->drawRadius+item->drawRadius));
	jointdef.localAnchorB.Set(0,0);
	world->worldSim->CreateJoint(&jointdef);
	b2Fixture * fix = item->body->GetFixtureList();
	b2Filter filter = b2Filter(fix->GetFilterData());
	filter.categoryBits = BOT;
	filter.maskBits = BOT;
	fix->SetFilterData(filter);
}

void Bot::detach(Item* item){
	b2JointEdge * je = item->body->GetJointList();
	while(je->other!=this->body && je != NULL){
		je = je->next;
	}
	world->worldSim->DestroyJoint(je->joint);
	b2Fixture * fix = item->body->GetFixtureList();
	b2Filter filter = b2Filter(fix->GetFilterData());	
	filter.categoryBits = ITEM;
	filter.maskBits = (ITEM|CONTAINER);
	fix->SetFilterData(filter);
}

bool Mover::moveTowardTarget(){
	b2Vec2 position = moverbody->GetPosition();
	b2Vec2 direction = target - position;
	b2Vec2 velocity = moverbody->GetLinearVelocity();	
	if(direction.LengthSquared()<6){
		return false;
	}
	else{
		//which direction should I be moving?
		//which direction am I moving?
		b2Vec2 modVelocity = direction;
		direction -= velocity;
		direction *= 4;
		moverbody->ApplyForce(direction,position);
	}
	return true;
}

bool Mover::turnTowardTarget(){
	//float currentAngle;
	//float targetAngle;
	return false;
}

bool Mover::stop(){
	moverbody->SetLinearVelocity(b2Vec2(0,0));
	return false;
}

/**ObserverSubject*/
void ObserverSubject::registerObserver(Observer * obs){
	for(unsigned int i = 0; i<observers.size(); i++){
		if(observers[i]==obs){
			return;
		}
	}
	observers.push_back(obs);
}
void ObserverSubject::unregisterObserver(Observer * obs){
	for(unsigned int i = 0; i<observers.size(); i++){
		if(observers[i]==obs){
			observers.erase(observers.begin()+i);
		}
	}
}
void ObserverSubject::notifyObservers(){
	for(unsigned int i = 0; i < observers.size(); i++){
		observers[i]->notify();
	}
}